/*
 *  ffmpeg中间封装接口
 */
#ifndef _FFMPEG_CODEC_H_
#define _FFMPEG_CODEC_H_

#ifdef __cplusplus
extern "C"
{
#endif

#include <stdint.h>

// 编码/解码
typedef enum {
    CODEC_TYPE_ENCODE = 0,
    CODEC_TYPE_DECODE,
} FFCodecType;

// 格式大全
typedef enum {
    CODEC_FORMAT_NONE = 0,

    //音频编码
    CODEC_FORMAT_PCM = 1000,
    CODEC_FORMAT_AAC,

    //照片编码
    CODEC_FORMAT_JPEG = 1100,

    //视频编码
    CODEC_FORMAT_H264 = 1200,
    CODEC_FORMAT_H265,
    CODEC_FORMAT_MJPEG,

    //RGB排列
    CODEC_FORMAT_RGB = 2000,
    CODEC_FORMAT_BGR,

    CODEC_FORMAT_ARGB,
    CODEC_FORMAT_ABGR,
    
    CODEC_FORMAT_RGBA,
    CODEC_FORMAT_BGRA,

    //YUV排列
    CODEC_FORMAT_YUV420P = 2100,
    CODEC_FORMAT_YUV422P,

    CODEC_FORMAT_YVU420P,
    CODEC_FORMAT_YVU422P,

    CODEC_FORMAT_YUV420SP, // 即 NV12, UV交错排列
    CODEC_FORMAT_YUV422SP, // 即 NV16, UV交错排列

    CODEC_FORMAT_YVU420SP, // 即 NV21, VU交错排列
    CODEC_FORMAT_YVU422SP, // 即 NV61, VU交错排列

    CODEC_FORMAT_YUV400, // 灰度图
} FFCodecFormat;

// YUV或RGB图像数据存储结构体
typedef struct {
    FFCodecFormat format;
    uint32_t width;
    uint32_t height;
    uint32_t pb; //每像素字节数
    uint8_t *map;
} FFCodec_Map;

/*
 *  视频编解码初始化
 *  参数:
 *      type: 编码还是解码
 *      format: 被编解/码数据的格式
 *      inputFormat: 编码时使用,其它时候填 CODEC_FORMAT_NONE 即可
 *      groupSize: 一组图像中的图像数量,图像运动剧烈可以设小点,当然数据量也会变大
 *      bFrame: 启用B帧数量,B帧可以提高压缩率,但依赖前后帧解码(不适用于网络直播),写0不启用
 *  返回: 控制句柄, NULL失败
 */
void* ffcodec_init(
    FFCodecType type,
    FFCodecFormat format,
    FFCodecFormat inputFormat,
    uint32_t width, // 编码时有效 720
    uint32_t height, // 编码时有效 480
    uint32_t fps, // 编码时有效 30
    uint32_t groupSize, // 编码时有效 20
    uint32_t bFrame // 编码时有效 0
    );

void ffcodec_deinit(void *handle);

/*
 *  视频解码
 *  参数:
 *      buff: 一帧待解码数据
 *      buffSize: buff字节长度
 *      yuvMap: 数组yuvMap[3]的首地址,用于返回yuv数据(不需要用后释放)
 *      rgbMap: 返回rgb数据,需提前配置好map、width、height、format参数(自行管理内存分配和释放)
 *  返回: 0成功 -1失败
 */
int32_t ffcodec_decode(
    void *handle,
    uint8_t *buff,
    uint32_t buffSize,
    FFCodec_Map yuvMap[3],
    FFCodec_Map *rgbMap);

/*
 *  视频编码
 *  参数:
 *      yuvMap: 数组yuvMap[3]的首地址,存储yuv数据,需自行分配好内存并设置正确width、height、format参数
 *      frameBuff: 返回编码后数据指针,请在下次调用该函数前使用完(不需要用后释放)
 *      frameBuffSize: 返回frameBuff数据长度
 *  返回: 0成功 -1失败
 *  注意: yuv编码h264/h265时,由于滤波需要,前面约10帧都不会返回数据,并非系统异常
 */
int32_t ffcodec_encode(
    void *handle,
    FFCodec_Map yuvMap[3],
    uint8_t **frameBuff,
    uint32_t *frameBuffSize);

//yuv转rgb,返回0成功,rgbMap需提前配置好map、width、height、format参数
int32_t ffcodec_YUV_to_RGB(FFCodec_Map yuvMap[3], FFCodec_Map *rgbMap);

// ----- 其它工具方法 -----

//查找h264/265帧位置,返回offset,-1失败
int32_t h26xFindFrame(const uint8_t *buff, uint32_t buffLen, int32_t *frameSize, char *type);

//移动缓冲区,配合H26xFindFrame()使用
void h26xMoveBuff(uint8_t *buff, int32_t *buffLen, int32_t *buffOffset, int32_t *frameSize);

#ifdef __cplusplus
}
#endif

#endif // _FFMPEG_CODEC_H_
